package top.fangw.tenant.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import top.fangw.common.core.entity.BaseIdNameVo;
import top.fangw.common.mybatis.annotation.DyDataSource;
import top.fangw.common.mybatis.service.BaseTreeService;
import top.fangw.tenant.mapper.PackageJonApplicationMapper;
import top.fangw.tenant.mapper.PackageJonMenuMapper;
import top.fangw.tenant.pojo.dto.TenantPackageAddDto;
import top.fangw.tenant.pojo.dto.TenantPackageQueryDto;
import top.fangw.tenant.pojo.entity.PackageJonApplication;
import top.fangw.tenant.pojo.entity.PackageJonMenu;
import top.fangw.tenant.pojo.entity.TenantPackageInfo;
import top.fangw.tenant.mapper.TenantPackageInfoMapper;
import top.fangw.tenant.service.ITenantPackageInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 用途：提供不同类型的套餐时长、开发功能菜单范围 服务实现类
 * </p>
 *
 * @author fangw
 * @since 2024-01-16
 */
@Service
@RequiredArgsConstructor
public class TenantPackageInfoServiceImpl extends ServiceImpl<TenantPackageInfoMapper, TenantPackageInfo> implements ITenantPackageInfoService {

    private final PackageJonMenuMapper packageJonMenuMapper;

    private final PackageJonApplicationMapper packageJonApplicationMapper;

    @Override
    @DyDataSource
    @Transactional(rollbackFor = Exception.class)
    public void add(TenantPackageAddDto tenantPackageAddDto) {
        TenantPackageInfo tenantPackageInfo = BeanUtil.copyProperties(tenantPackageAddDto, TenantPackageInfo.class);
        Assert.notNull(tenantPackageInfo.getDuration(), "套餐时长不能为空");
        // 添加套餐信息
        this.save(tenantPackageInfo);
        //  添加套餐应用信息
        if (tenantPackageAddDto.getApplicationIds() != null && !tenantPackageAddDto.getApplicationIds().isEmpty()) {
            tenantPackageAddDto.getApplicationIds().forEach(applicationId -> {
                //  添加套餐应用信息
                PackageJonApplication packageJonApplication = new PackageJonApplication();
                packageJonApplication.setApplicationId(applicationId)
                        .setTenantPackageId(tenantPackageInfo.getId());
                packageJonApplicationMapper.insert(packageJonApplication);
            });
        }
        //  添加套餐功能菜单信息
        if (tenantPackageAddDto.getMenuIds() != null && !tenantPackageAddDto.getMenuIds().isEmpty()) {
            tenantPackageAddDto.getMenuIds().forEach(menuId -> {
                //  添加套餐功能菜单信息
                PackageJonMenu packageJonMenu = new PackageJonMenu();
                packageJonMenu.setMenuId(menuId)
                        .setTenantPackageId(tenantPackageInfo.getId());
                packageJonMenuMapper.insert(packageJonMenu);
            });
        }
    }

    @Override
    @DyDataSource
    public void updateTenantPackage(TenantPackageAddDto tenantPackageAddDto) {
        TenantPackageInfo tenantPackageInfo = BeanUtil.copyProperties(tenantPackageAddDto, TenantPackageInfo.class);
        Assert.notNull(tenantPackageInfo.getDuration(), "套餐时长不能为空");
        // 添加套餐信息
        this.updateById(tenantPackageInfo);
        // 获取原有的套餐应用信息
        List<String> oldApplicationIds = packageJonApplicationMapper.selectApplicationIdsByTenantPackageId(tenantPackageInfo.getId());
        List<String> oldDelApplications = new ArrayList<>();
        List<String> oldAddApplications = new ArrayList<>();
        List<String> applicationIds = tenantPackageAddDto.getApplicationIds();
        dealOldData(oldApplicationIds, oldDelApplications, oldAddApplications, applicationIds);
        if (!applicationIds.isEmpty()) {
            applicationIds.forEach(applicationId -> {
                //  添加套餐应用信息
                PackageJonApplication packageJonApplication = new PackageJonApplication();
                packageJonApplication.setApplicationId(applicationId)
                        .setTenantPackageId(tenantPackageInfo.getId());
                packageJonApplicationMapper.insert(packageJonApplication);
            });
        }
        // 删除套餐应用信息
        if (!oldDelApplications.isEmpty()) {
            oldDelApplications.forEach(oldDelApplication -> {
                packageJonApplicationMapper.deleteByIdAct(tenantPackageInfo.getId(),oldDelApplication);
            });
        }

        // 获取原有的套餐功能菜单信息
        List<String> oldMenuIds = packageJonMenuMapper.selectMenuIdsByTenantPackageId(tenantPackageInfo.getId());
        List<String> oldDelMenus = new ArrayList<>();
        List<String> oldAddMenus = new ArrayList<>();
        List<String> menuIds = tenantPackageAddDto.getMenuIds();
        dealOldData(oldMenuIds, oldDelMenus, oldAddMenus, menuIds);
        if (!menuIds.isEmpty()) {
            menuIds.forEach(menuId -> {
                //  添加套餐应用信息
                PackageJonMenu packageJonMenu = new PackageJonMenu();
                packageJonMenu.setMenuId(menuId)
                        .setTenantPackageId(tenantPackageInfo.getId());
                packageJonMenuMapper.insert(packageJonMenu);
            });
        }
        // 删除套餐应用信息
        if (!oldDelMenus.isEmpty()) {
            oldDelMenus.forEach(oldDelMenu -> {
                packageJonMenuMapper.deleteByIdAct(tenantPackageInfo.getId(),oldDelMenu);
            });
        }
    }

    @Override
    @DyDataSource
//    @GlobalTransactional
    public void delete(String id) {
        // 删除套餐信息
        this.removeById(id);
        // 删除套餐应用信息
        packageJonApplicationMapper.deleteByPackageId(id);
        // 删除套餐功能菜单信息
        packageJonMenuMapper.deleteByPackageId(id);
    }

    @Override
    @DyDataSource
    public TenantPackageAddDto getDetail(String id) {
        TenantPackageInfo tenantPackageInfo = this.getById(id);
        Assert.notNull(tenantPackageInfo, "套餐信息不存在");
        TenantPackageAddDto tenantPackageAddDto = BeanUtil.copyProperties(tenantPackageInfo, TenantPackageAddDto.class);
        // 获取套餐应用信息
        List<String> applicationIds = packageJonApplicationMapper.selectApplicationIdsByTenantPackageId(id);
        tenantPackageAddDto.setApplicationIds(applicationIds);
        // 获取套餐功能菜单信息
        List<String> menuIds = packageJonMenuMapper.selectMenuIdsByTenantPackageId(id);
        tenantPackageAddDto.setMenuIds(menuIds);
        return tenantPackageAddDto;
    }

    @Override
    public IPage<TenantPackageInfo> pageList(TenantPackageQueryDto queryDto) {
        IPage<TenantPackageInfo> page = new Page<>(queryDto.getCurrent(), queryDto.getSize());
        LambdaQueryWrapper<TenantPackageInfo> queryWrapper = new LambdaQueryWrapper<TenantPackageInfo>().orderByAsc(TenantPackageInfo::getSort);
        if(StrUtil.isNotBlank(queryDto.getName())){
            queryWrapper.like(TenantPackageInfo::getName, queryDto.getName());
        }
        return this.baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public List<BaseIdNameVo> listPackage() {
        return this.baseMapper.listPackage();
    }

    private void dealOldData(List<String> oldApplicationIds, List<String> oldDelApplications, List<String> oldAddApplications, List<String> applicationIds) {
        if (oldApplicationIds != null && !oldApplicationIds.isEmpty()) {
            oldApplicationIds.forEach(oldApplicationId -> {
                if (!applicationIds.contains(oldApplicationId)) {
                    oldDelApplications.add(oldApplicationId);
                } else {
                    oldAddApplications.add(oldApplicationId);
                }
            });
        }
        ArrayList<String> applicationIdsCopy = new ArrayList<>(applicationIds);
        if (!applicationIdsCopy.isEmpty()) {
            applicationIdsCopy.forEach(applicationId -> {
                if (oldAddApplications.contains(applicationId)) {
                    applicationIds.remove(applicationId);
                }
            });
        }

    }
}
